#include <pthread.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>

#ifdef OS_LINUX
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#endif

#include "Base/lib/lib.common.h"
#include "Base/lib/getConf.h"
#include "Base/lib/lib.log.h"
#include "Base/lib/lib.conn.h"

#define MAX_EVT_NUM 30

extern pthread_mutexattr_t pmuattrMp;
extern pthread_mutex_t pmuMp;
extern pthread_condattr_t pconattrMp;
extern pthread_cond_t pconMp;

static int handleClientData(int fd);

void handleClientReq(void *arg){

	int dport;
	struct sockaddr_in serverAddr, clientAddr;
	int listenFD;
	int *clientFD, *cfdFlag;
	int sockNum;
	char line[128];
	socklen_t socklen;

	int epollFD, epEvtNum,epTempNum;
	struct epoll_event ev,epEvts[MAX_EVT_NUM];

	const char *port=getConfItem("WASD_SERVER_LISTEN_PORT");
	const char *clientNum=getConfItem("WASD_CONCURRENT_NUM");
	if(NULL==port){
		logIt(LOG_ERROR,"Cannot get the port from the conf file. Exiting...");
		listenFlag=FALSE;
	}else
		dport=atoi(port);

	if(NULL==clientNum){
		logIt(LOG_ERROR,"Cannot get the concurrent client numbers from the conf file. Exiting...");
		listenFlag=FALSE;
	}else
		sockNum=atoi(clientNum);

	/* Failed to get the port number from the conf file. Signal the condition_variable
	 * Mark the listenFlag and let the main process die */
	if(FALSE==listenFlag){
		pthread_cond_signal(&pconMp);
		exit(EXIT_FAILURE);
	}

	pthread_mutex_lock(&pmuMp);



	clientFD=(int *)malloc(sizeof(int)*sockNum);
	cfdFlag=(int*)malloc(sizeof(int)*sockNum);

	memset(cfdFlag, 0, sockNum);

	//serverAdd.sin_len=sizeof(struct sockaddr_in);

	bzero(&serverAddr, sizeof(listenFD));
	serverAddr.sin_family = AF_INET;
	serverAddr.sin_port = htons(dport);
	serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); /** INADDR_ANY means let the kernel pick up the address for you when a tcp connection comes.*/

	if(0!=(listenFD=socket(AF_INET,SOCK_STREAM,0))){
		listenFlag=FALSE;
		logIt(LOG_ERROR,"Cannot create the socket for listenFD.Exiting...");
		logIt(LOG_ERROR,"Errno:%s",strerror(errno));
		goto signal;
	}
	if(FALSE==setNonBlockingFD(listenFD)){
		listenFlag=FALSE;
		logIt(LOG_ERROR,"Failed to setNonBlock listenFD");
		goto signal;
	}
	if(0!=bind(listenFD,&serverAddr,sizeof(serverAddr))){
		listenFlag=FALSE;
		logIt(LOG_ERROR,"Cannot bind the socket for listenFD.Exiting...");
		logIt(LOG_ERROR,"Errno:%s",strerror(errno));
		goto signal;
	}

	if(0!=listen(listenFD,sockNum)){
		listenFlag=FALSE;
		logIt(LOG_ERROR,"Cannot listen the socket for listenFD.Exiting...");
		logIt(LOG_ERROR,"Errno:%s",strerror(errno));
/*		goto signal;*/
	}

signal:
	pthread_cond_signal(&pconMp);
	pthread_mutex_unlock(*pmuMp);
	if(FALSE==listenFlag){
		exit(EXIT_FAILURE);
	}

	epollFD=epoll_create(MAX_EVT_NUM);
	if(-1==epollFD){
		logIt(LOG_ERROR,"epoll_create failed for epollFD. Error message: %s",strerror(errno));
		goto exit_abnormal;
	}

	ev.events = EPOLLIN | EPOLLET;
	ev.data.fd = listenFD;
	/*Add listenFD into the epoll list */
	if(-1==epoll_ctl(epollFD,EPOLL_CTL_ADD,listenFD,&ev)){
		logIt(LOG_ERROR,"epoll_ctl failed for epollFD. Error message: %s",strerror(errno));
		goto exit_abnormal;
	}
	epEvtNum=1;

	while(1){
		int i;
		epTempNum=epoll_wait(epollFD,&epEvts,epEvtNum,-1);
		for(i=0;i<epTempNum;i++){
			if(listenFD==epEvts[i].data.fd){
				clientFD=accept(listenFD,&clientAddr,&socklen);
				logIt(LOG_INFO,"Accept new client connection from %s",inet_ntoa(clientAddr.sin_addr));
				ev.data.fd=clientFD;
				ev.events=EPOLLIN | EPOLLET;
				if(-1==epoll_ctl(epollFD,EPOLL_CTL_ADD,clientFD,&ev)){
					close(listenFD);
					logIt(LOG_ERROR,"epoll_ctl failed for new client connection. Error message: %s",strerror(errno));
					goto exit_abnormal;
				}
			}else{
				/*Epoll events from an existing connection*/
				handleClientData(&(epEvts[i]));
			}
		}
	}


exit_abnormal:
	listenFlag=FALSE;
	exit(0);
}

static int handleClientData(struct epoll_event *p_epEvt){
	if((p_epEvt->events) & EPOLLOUT){
		/*If write is ready*/

	}else if((p_epEvt->events) & EPOLLIN){
		/* if read is ready*/
	}

	return 0;

}
